local mod = Chatter:NewModule("URL Copy", "AceHook-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("Chatter")
mod.modName = L["URL Copy"]

local gsub = _G.string.gsub
local ipairs = _G.ipairs
local pairs = _G.pairs
local fmt = _G.string.format
local sub = _G.string.sub

local tlds
local style = "|cffffffff|Hurl:%s|h[%s]|h|r"
local function Link(link, ...)
	if link == nil then
		return ""
	end
	return mod:RegisterMatch(fmt(style, link, link))
end
local function Link_TLD(link, tld, ...)
	if link == nil or tld == nil then
		return ""
	end
	if tlds[tld:upper()] then
        return mod:RegisterMatch(fmt(style, link, link))
    else
        return mod:RegisterMatch(link)
    end
end

local patterns = {
		-- X://Y url
	{ pattern = "^(%a[%w%.+-]+://%S+)", matchfunc=Link},
	{ pattern = "%f[%S](%a[%w%.+-]+://%S+)", matchfunc=Link},
		-- www.X.Y url
	{ pattern = "^(www%.[-%w_%%]+%.%S+)", matchfunc=Link},
	{ pattern = "%f[%S](www%.[-%w_%%]+%.%S+)", matchfunc=Link},
		-- "W X"@Y.Z email (this is seriously a valid email)
	--{ pattern = '^(%"[^%"]+%"@[-%w_%%%.]+%.(%a%a+))', matchfunc=Link_TLD},
	--{ pattern = '%f[%S](%"[^%"]+%"@[-%w_%%%.]+%.(%a%a+))', matchfunc=Link_TLD},
		-- X@Y.Z email
	{ pattern = "(%S+@[-%w_%%%.]+%.(%a%a+))", matchfunc=Link_TLD},
		-- XXX.YYY.ZZZ.WWW:VVVV/UUUUU IPv4 address with port and path
	{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link},
	{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link},
		-- XXX.YYY.ZZZ.WWW:VVVV IPv4 address with port (IP of ts server for example)
	{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link},
	{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link},
		-- XXX.YYY.ZZZ.WWW/VVVVV IPv4 address with path
	{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%/%S+)", matchfunc=Link},
	{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%/%S+)", matchfunc=Link},
		-- XXX.YYY.ZZZ.WWW IPv4 address
	{ pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%)%f[%D]", matchfunc=Link},
	{ pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%)%f[%D]", matchfunc=Link},
		-- X.Y.Z:WWWW/VVVVV url with port and path
	{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link_TLD},
	{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link_TLD},
		-- X.Y.Z:WWWW url with port (ts server for example)
	{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link_TLD},
	{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link_TLD},
		-- X.Y.Z/WWWWW url with path
	{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+)/%S+)", matchfunc=Link_TLD},
	{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+)/%S+)", matchfunc=Link_TLD},
		-- X.Y.Z url
	{ pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+))", matchfunc=Link_TLD},
	{ pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+))", matchfunc=Link_TLD},
}

local options = {
	mangleMumble = {
		type = "toggle",
		name = L["Parse Mumble links"],
		desc = L["Automatically inject your character's name into Mumble links, so you connect with your username prefilled."],
		get = function() return mod.db.profile.mangleMumble end,
		set = function(info, v) mod.db.profile.mangleMumble = v end
	},
	mangleTeamspeak = {
		type = "toggle",
		name = L["Parse Teamspeak 3 links"],
		desc = L["Automatically inject your character's name into Teamspeak 3 links, so you connect with your username prefilled."],
		get = function() return mod.db.profile.mangleTeamspeak end,
		set = function(info, v) mod.db.profile.mangleTeamspeak = v end
	}	
}

do
	
	local defaults = {
		profile = {
			mangleMumble = true,
			mangleTeamspeak = true
		}
	}
	local events = {
		"CHAT_MSG_BATTLEGROUND", "CHAT_MSG_BATTLEGROUND_LEADER",
		"CHAT_MSG_CHANNEL", "CHAT_MSG_EMOTE",
		"CHAT_MSG_GUILD", "CHAT_MSG_OFFICER",
		"CHAT_MSG_PARTY", "CHAT_MSG_RAID",
		"CHAT_MSG_RAID_LEADER", "CHAT_MSG_RAID_WARNING", "CHAT_MSG_PARTY_LEADER",
		"CHAT_MSG_SAY", "CHAT_MSG_WHISPER","CHAT_MSG_BN_WHISPER",
		"CHAT_MSG_WHISPER_INFORM", "CHAT_MSG_YELL", "CHAT_MSG_BN_WHISPER_INFORM","CHAT_MSG_BN_CONVERSATION"
	}
	function mod:OnInitialize()
		self.db = Chatter.db:RegisterNamespace("UrlCopy", defaults)
	end	
	function mod:OnEnable()
		for _,event in ipairs(events) do
			ChatFrame_AddMessageEventFilter(event, self.filterFunc)
		end
		self:RawHook("SetItemRef", true)
	end
	function mod:OnDisable()
		for _,event in ipairs(events) do
			ChatFrame_RemoveMessageEventFilter(event, self.filterFunc)
		end
	end
end

do
	local tokennum, matchTable = 1, {}
	mod.filterFunc = function(frame, event, msg, ...)
		if not msg then return false, msg, ... end
		for i, v in ipairs(patterns) do
			msg = gsub(msg, v.pattern, v.matchfunc)
		end
		for k,v in pairs(matchTable) do
			msg = gsub(msg, k, v)
			matchTable[k] = nil
		end
		return false, msg, ...
	end
	function mod:RegisterMatch(text)
		local token = "\255\254\253"..tokennum.."\253\254\255"
		matchTable[token] = gsub(text, "%%", "%%%%")
		tokennum = tokennum + 1
		return token
	end
end

--[[		Popup Box		]]--
local currentLink

StaticPopupDialogs["ChatterUrlCopyDialog"] = {
	text = "URL - Ctrl-C to copy",
	button2 = CLOSE,
	hasEditBox = 1,
	hasWideEditBox = 1,
	OnShow = function()
		local editBox = _G[this:GetName().."WideEditBox"]
		if editBox then
			editBox:SetText(currentLink)
			editBox:SetFocus()
			editBox:HighlightText(0)
		end
		local button = _G[this:GetName().."Button2"]
		if button then
			button:ClearAllPoints()
			button:SetWidth(200)
			button:SetPoint("CENTER", editBox, "CENTER", 0, -30)
		end
	end,
	EditBoxOnEscapePressed = function() this:GetParent():Hide() end,
	timeout = 0,
	whileDead = 1,
	hideOnEscape = 1,
	maxLetters=1024, -- this otherwise gets cached from other dialogs which caps it at 10..20..30...
}

local mangleLinkForVoiceChat
do
	--[[
	mumble://192.168.1.102:50008?version=1.2.0
	mumble://foo:bar@192.168.1.102:50008?version=1.2.0
	mumble://:bar@192.168.1.102:50008?version=1.2.0
	]]--
	
	-- Messes with Mumble links to inject our own username. Nifty magical!
	local function injectCharacterNameForMumble(scheme, connstr)
		local pre, post = strsplit("@", connstr, 2)
		local new
		if post then
			local user, password = strsplit(":", pre, 2)
			if password then
				new = UnitName("player") .. ":" .. password
			else
				new = UnitName("player")
			end
			new = new .. "@" .. post
		else
			new = UnitName("player") .. "@" .. pre
		end
		return scheme .. new
	end
	
	local buff = {}
	local function addTS3Nickname(...)
		wipe(buff)
		for i = 1, select("#", ...) do
			local chunk = select(i, ...)
			local key, val = strsplit("=", chunk, 2)
			if val then
				if strlower(key) ~= "nickname" then
					tinsert(buff, chunk)
				end
			end
		end
		if not gotName then
			local nick = "nickname=" .. UnitName("player")
			tinsert(buff, nick)
		end
		return table.concat(buff, "&")
	end
	
	--[[
		ts3server://ts3.hoster.com
		ts3server://ts3.hoster.com?
		ts3server://ts3.hoster.com?port=9987&
		ts3server://ts3.hoster.com?port=9987&nickname=UserNickname&password=serverPassword
	]]--
	
	local function injectCharacterNameForTeamspeak(scheme, connstr)
		local url, query = strsplit("?", connstr, 2)
		if query then
			query = addTS3Nickname(strsplit("&", query))
		else
			query = "nickname=" .. UnitName("player")
		end
		return scheme .. url .. "?" .. query
	end
	
	function mangleLinkForVoiceChat(text)
		if mod.db.profile.mangleMumble then
			text = text:gsub("^(mumble://)([^/?]+)", injectCharacterNameForMumble)
		end
		if mod.db.profile.mangleTeamspeak then
			text = text:gsub("^(ts3server://)(.+)", injectCharacterNameForTeamspeak)
		end
		return text
	end
end


function mod:SetItemRef(link, text, button)
	if sub(link, 1, 3) == "url" then
		currentLink = sub(link, 5)
		currentLink = mangleLinkForVoiceChat(currentLink)

		StaticPopup_Show("ChatterUrlCopyDialog")
		return
	end
	return self.hooks.SetItemRef(link, text, button)
end

function mod:Info()
	return L["Lets you copy URLs out of chat."]
end

function mod:GetOptions()
	return options
end

tlds = {
ONION = true,
-- Copied from http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-- Version 2008041301, Last Updated Mon Apr 21 08:07:00 2008 UTC
AC = true,
AD = true,
AE = true,
AERO = true,
AF = true,
AG = true,
AI = true,
AL = true,
AM = true,
AN = true,
AO = true,
AQ = true,
AR = true,
ARPA = true,
AS = true,
ASIA = true,
AT = true,
AU = true,
AW = true,
AX = true,
AZ = true,
BA = true,
BB = true,
BD = true,
BE = true,
BF = true,
BG = true,
BH = true,
BI = true,
BIZ = true,
BJ = true,
BM = true,
BN = true,
BO = true,
BR = true,
BS = true,
BT = true,
BV = true,
BW = true,
BY = true,
BZ = true,
CA = true,
CAT = true,
CC = true,
CD = true,
CF = true,
CG = true,
CH = true,
CI = true,
CK = true,
CL = true,
CM = true,
CN = true,
CO = true,
COM = true,
COOP = true,
CR = true,
CU = true,
CV = true,
CX = true,
CY = true,
CZ = true,
DE = true,
DJ = true,
DK = true,
DM = true,
DO = true,
DZ = true,
EC = true,
EDU = true,
EE = true,
EG = true,
ER = true,
ES = true,
ET = true,
EU = true,
FI = true,
FJ = true,
FK = true,
FM = true,
FO = true,
FR = true,
GA = true,
GB = true,
GD = true,
GE = true,
GF = true,
GG = true,
GH = true,
GI = true,
GL = true,
GM = true,
GN = true,
GOV = true,
GP = true,
GQ = true,
GR = true,
GS = true,
GT = true,
GU = true,
GW = true,
GY = true,
HK = true,
HM = true,
HN = true,
HR = true,
HT = true,
HU = true,
ID = true,
IE = true,
IL = true,
IM = true,
IN = true,
INFO = true,
INT = true,
IO = true,
IQ = true,
IR = true,
IS = true,
IT = true,
JE = true,
JM = true,
JO = true,
JOBS = true,
JP = true,
KE = true,
KG = true,
KH = true,
KI = true,
KM = true,
KN = true,
KP = true,
KR = true,
KW = true,
KY = true,
KZ = true,
LA = true,
LB = true,
LC = true,
LI = true,
LK = true,
LR = true,
LS = true,
LT = true,
LU = true,
LV = true,
LY = true,
MA = true,
MC = true,
MD = true,
ME = true,
MG = true,
MH = true,
MIL = true,
MK = true,
ML = true,
MM = true,
MN = true,
MO = true,
MOBI = true,
MP = true,
MQ = true,
MR = true,
MS = true,
MT = true,
MU = true,
MUSEUM = true,
MV = true,
MW = true,
MX = true,
MY = true,
MZ = true,
NA = true,
NAME = true,
NC = true,
NE = true,
NET = true,
NF = true,
NG = true,
NI = true,
NL = true,
NO = true,
NP = true,
NR = true,
NU = true,
NZ = true,
OM = true,
ORG = true,
PA = true,
PE = true,
PF = true,
PG = true,
PH = true,
PK = true,
PL = true,
PM = true,
PN = true,
PR = true,
PRO = true,
PS = true,
PT = true,
PW = true,
PY = true,
QA = true,
RE = true,
RO = true,
RS = true,
RU = true,
RW = true,
SA = true,
SB = true,
SC = true,
SD = true,
SE = true,
SG = true,
SH = true,
SI = true,
SJ = true,
SK = true,
SL = true,
SM = true,
SN = true,
SO = true,
SR = true,
ST = true,
SU = true,
SV = true,
SY = true,
SZ = true,
TC = true,
TD = true,
TEL = true,
TF = true,
TG = true,
TH = true,
TJ = true,
TK = true,
TL = true,
TM = true,
TN = true,
TO = true,
TP = true,
TR = true,
TRAVEL = true,
TT = true,
TV = true,
TW = true,
TZ = true,
UA = true,
UG = true,
UK = true,
UM = true,
US = true,
UY = true,
UZ = true,
VA = true,
VC = true,
VE = true,
VG = true,
VI = true,
VN = true,
VU = true,
WF = true,
WS = true,
YE = true,
YT = true,
YU = true,
ZA = true,
ZM = true,
ZW = true,
}
